package com.afdor.rws.event.driven.entities;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NonNull;
import lombok.ToString;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 事件聚合根
 *
 * @author 悭梵
 * @date Created in 2018-08-14 9:56
 */
@ToString
@EqualsAndHashCode
public class AggregationEvent extends Event<List<Event>> implements Cloneable {

    /**
     * 冻结事件修改操作
     */
    private final AtomicBoolean frozenModify = new AtomicBoolean();
    /**
     * 事件管理器中的事件队列
     */
    @Getter
    protected final List<Event> childEventList = new ArrayList<>(20);

    AggregationEvent() {
        setType(Type.AGGREGATION_ROOT);
    }

    public boolean hasEvent(@NonNull Event event) {
        checkup();
        return this.childEventList.contains(event);
    }


    public void addEvent(@NonNull Event event) {
        checkup();
        String parentId = event.getParentId();
        if (parentId == null || StringUtils.isBlank(parentId)) {
            event.setParentId(this.getId());
            event.setPath(EVENT_PATH_SPLIT + this.getId() + EVENT_PATH_SPLIT + event.getId());
        } else if (!Objects.equals(parentId, this.getId())) {
            throw new IllegalStateException("事件[" + event + "]中存在parentId已存在，无法执行聚合提交操作。请调整业务或分步提交。");
        }
        this.childEventList.add(event);
    }

    public void removeEvent(@NonNull Event event) {
        checkup();
        this.childEventList.remove(event);
    }

    public void clearEvent() {
        checkup();
        this.childEventList.clear();
    }

    public void commit() {
        this.setStatus(Status.EXECUTING_EVENT_BUS);
        this.frozenModify(true);
    }

    public void rollback() {
        this.setStatus(Event.Status.ROLLEDBACK_EVENT_BUS);
        this.frozenModify(false);
    }

    @Override
    public void setSource(List<Event> source) {
        // to do nothing
    }

    public void setSendType(SendType sendType, SendType childSendType) {
        super.setSendType(sendType);
        this.childEventList.forEach(event -> event.setSendType(childSendType));
    }

    /**
     * 冻结事件队列操作
     *
     * @param newFrozenEventList 生成冻结事件队列
     */
    private void frozenModify(boolean newFrozenEventList) {
        checkup();
        if (newFrozenEventList) {
            super.setSource(Collections.unmodifiableList(new ArrayList<Event>(childEventList)));
        }
        clearEvent();
        frozenModify.compareAndSet(Boolean.FALSE, Boolean.TRUE);
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    /**
     * 验证
     */
    private void checkup() {
        if (frozenModify.get()) {
            throw new IllegalStateException("事件队列已冻结，不能执行该操作");
        }
    }

    @ToString
    public static class EventBuilder {
        /**
         * 事件源
         */
        @NonNull
        private List<Event> source;

        public EventBuilder source(@NonNull List<Event> source) {
            this.source = source;
            return this;
        }

        /**
         * 生成Type.AGGREGATION_ROOT事件对象
         *
         * @return
         */
        public AggregationEvent build() {
            AggregationEvent event = new AggregationEvent();
            if (this.source != null) {
                event.childEventList.addAll(this.source);
            }
            event.eventSourceName = Type.AGGREGATION_ROOT.getDefaultSourceName();
            event.init();
            return event;
        }

    }
}
